package com.atguigu.service.impl;

import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.AsyncCartInfoService;
import com.atguigu.service.CartInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author fumeng
 * @since 2021-11-11
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    AsyncCartInfoService asyncCartInfoService;



    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        /**
         * a.先查询数据库中是否有记录
         *    根据skuId(商品id),userId(此时是临时id)
         */
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("sku_id", skuId);
        wrapper.eq("user_id", userId);
        CartInfo cartInfo = baseMapper.selectOne(wrapper);
        //数据库中有数据，
        if (cartInfo!=null){
            //商品数量相加
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            //更新实时价格
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            //更新数据库 需要优化
            asyncCartInfoService.updateCartInfo(cartInfo);
        }else {
            //数据库没有数据，插入
            cartInfo = new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            //添加购物车价格
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setSkuNum(skuNum);
            //添加实时价格
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            //默认页面勾选购物车信息
            cartInfo.setIsChecked(1);
            asyncCartInfoService.saveCartInfo(cartInfo);
        }
        /**
         * b.在存储在redis中一份购物车信息
         */
        String cartKey = getCartKey(userId);
        redisTemplate.boundHashOps(cartKey).put(skuId.toString(),cartInfo);
        //需要一个过期时间
        setCartKeyExpire(cartKey);
    }

    //设置过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    //在redis中建立key
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }



    //购物车列表
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //当用户没有登录
        if (!StringUtils.isEmpty(userTempId)) {
            //从数据库中查询数据
            cartInfoList = getUserCartList(userTempId);
        }
        //当用户登录之后
        if (!StringUtils.isEmpty(userId)) {
            //查询未登录用户购物车信息 方便合并
            List<CartInfo> noLoginCartInfoList = getUserCartList(userTempId);
            if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
                //当未登录购物车中有数据则合并。
                cartInfoList = mergeCartList(noLoginCartInfoList, userId);
                //合并完成之后，删除未登录购物车
                deleteNoLoginCartList(userTempId);
            }
            //细节问题：如果未登录数据是空 或者 userTempId 是空，都会直接查询数据库(实在不行就去掉)
            if (CollectionUtils.isEmpty(noLoginCartInfoList) || StringUtils.isEmpty(userTempId)) {
                // 登录的userId不为空，查询userId 购物车
                cartInfoList = getUserCartList(userId);
            }
        }
        return cartInfoList;

    }

    //这个方法不是用来做缓存 用来更新缓存
    @Override
    public List<CartInfo> queryFromDbToRedis(String userTempId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userTempId);
        List<CartInfo> dbCartInfoList = baseMapper.selectList(wrapper);
        //如果数据库中不存在用户添加的数据
        if (CollectionUtils.isEmpty(dbCartInfoList)){
            return dbCartInfoList;
        }
        String cartKey = getCartKey(userTempId);
        HashMap<String, CartInfo> map = new HashMap<>();
        for (CartInfo cartInfo : dbCartInfoList) {
            //方式一
            //redisTemplate.opsForHash().put(cartKey,cartInfo.getSkuId().toString(),cartInfo);
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            map.put(cartInfo.getSkuId().toString(),cartInfo);
        }
        redisTemplate.opsForHash().putAll(cartKey,map);
        //设置过期时间
        setCartKeyExpire(cartKey);
        return dbCartInfoList;
    }
    //根据userId获取购物车列表数据
    private List<CartInfo> getUserCartList(String oneOfUserId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //如果临时用户id为空
        if (StringUtils.isEmpty(oneOfUserId)) {
            return cartInfoList;
        }
        cartInfoList = queryFromDbToRedis(oneOfUserId);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            // 循环遍历获取里面的数据，原因？查询购物车列表时，应该有排序功能！ 按照商品的更新时间进行排序
            // 由于我们这个table 没有更新时间字段 | 在此按照id 进行排序。
            cartInfoList.sort(new Comparator<CartInfo>() {
                @Override
                public int compare(CartInfo o1, CartInfo o2) {
                    return o1.getId().compareTo(o2.getId());
                }
            });
        }
        // 返回排序好的集合数据
        return cartInfoList;
    }

    // 合并购物车数据
    private List<CartInfo> mergeCartList(List<CartInfo> noLoginCartInfoList, String userId) {
        List<CartInfo> loginCartInfoList = getUserCartList(userId);
        //就相当于迭代list往map中放数据
        Map<Long, CartInfo> loginCartInfoMap = loginCartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
            Long skuId = noLoginCartInfo.getSkuId();
            //判断登录和未登录有相同商品
            if (loginCartInfoMap.containsKey(skuId)) {
                // 商品的数量进行相加操作
                CartInfo loginCartInfo = loginCartInfoMap.get(skuId);
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + noLoginCartInfo.getSkuNum());
                //细节: 合并选中细节 未登录购物车选中状态，那么则数据库为选中状态
                if (noLoginCartInfo.getIsChecked().intValue() == 1) {
                    loginCartInfo.setIsChecked(1);
                }
                // 更新数据库操作
                asyncCartInfoService.updateCartInfo(loginCartInfo);
            } else {
                // 没有包含的说明没有对应的商品，noLoginCartInfo 放入数据  39
                // 将未登录用户Id 设置成已登录的用户Id
                noLoginCartInfo.setUserId(userId);
                asyncCartInfoService.saveCartInfo(noLoginCartInfo);
            }
        }
        //把缓存里面的信息全部更新一下
        List<CartInfo> cartInfoList = queryFromDbToRedis(userId);
        return cartInfoList;
    }

    // 删除未登录购物车数据
    private void deleteNoLoginCartList(String userTempId) {
        asyncCartInfoService.deleteCartInfo(userTempId,null);
        // 获取缓存的key
        String cartKey = getCartKey(userTempId);
        // 判断缓存有这个key没有
        Boolean flag = redisTemplate.hasKey(cartKey);
        if (flag) {
            redisTemplate.delete(cartKey);
        }
    }


    //商品的选中
    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        //修改redis中选中
        String cartKey = getCartKey(userId);
        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //查看是否有skuid对应的商品信息
        if (boundHashOperations.hasKey(skuId.toString())){
            CartInfo redisCartInfo = (CartInfo)boundHashOperations.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //设置更新redis
            boundHashOperations.put(skuId.toString(),redisCartInfo);
            //重新设置过期时间
            setCartKeyExpire(cartKey);
        }
        //修改数据库中的数据选中
        asyncCartInfoService.checkCart(userId,skuId,isChecked);
    }

    //删除购物车商品
    @Override
    public void deleteCart(String userId, Long skuId) {
        //拿到edis中数据
        String cartKey = getCartKey(userId);
        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //查看是否有skuid对应的商品信息
        if (boundHashOperations.hasKey(skuId.toString())){
            //删除数据
            boundHashOperations.delete(skuId.toString());
        }
        //数据库删除
        asyncCartInfoService.deleteCartInfo(userId,skuId);
    }

    //查看选中的商品
    @Override
    public List<CartInfo> getSelectedProduct(String userId) {
        //装勾选的商品
        ArrayList<CartInfo> list = new ArrayList<>();
        //拿到redis中数据
        String cartKey = getCartKey(userId);
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartInfoList)){
            for (CartInfo cartInfo : cartInfoList) {
                //拿到勾选的商品
                if(cartInfo.getIsChecked()==1){
                    list.add(cartInfo);
                }
            }
        }
        return list;
    }



}
